import os
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtSerialPort import QSerialPort
from lib.fota_sota.fota_lib import FOTAUpgrader
from lib.fota_sota.sota_lib import SOTAManager, SerialReader
from lib.uplink_downlink import event_report, command_issue

class SerialThread(QThread):
    serialReady = pyqtSignal(list)  # 定义信号用于传递串口回复
    updateStepSignal = pyqtSignal(str, int, str)  # 端口名, 步骤索引, 状态
    updateDetailSignal = pyqtSignal(str, int, str)  # 端口名, 步骤索引, 详细信息
    finished = pyqtSignal()  # 添加完成信号

    def __init__(self, port_name):
        super().__init__()
        self.port_name = port_name
        self.serial = None  # 在子线程中创建实例
        self.running = True  # 控制线程运行的标志

    def stop(self):
        """停止线程执行"""
        self.running = False

    def run(self):
        """在单独的线程中运行测试"""
        try:
            # 在线程内创建串口对象
            self.serial = QSerialPort()
            self.serial.setPortName(self.port_name)
            self.serial.setBaudRate(QSerialPort.Baud115200)

            if not self.serial.open(QSerialPort.ReadWrite):
                raise Exception("无法打开串口")

            print(f"正在测试: {self.port_name}")
            self.updateDetailSignal.emit(self.port_name, 0, f"<p>开始测试串口: {self.port_name}</p>")
            
            # 执行第一步：数据上报测试
            report_success = self.execute_report_test()
            
            # 如果数据上报成功，执行第二步：指令下发测试
            if report_success:
                command_success = self.execute_command_test()
                # 如果指令下发成功，执行第三步：FOTA升级测试
                if command_success:
                    fota_success = self.execute_fota_test()
                    # 如果FOTA升级成功，执行第四步：SOTA下载测试
                    if fota_success:
                        self.execute_sota_test()
                
        except Exception as e:
            error_msg = str(e)
            print(f"测试失败: {error_msg}")
            self.updateDetailSignal.emit(self.port_name, 0, f"<p style='color:red'>测试失败: {error_msg}</p>")
            self.updateStepSignal.emit(self.port_name, 0, "failed")
        finally:
            if self.serial and self.serial.isOpen():
                self.serial.close()
                self.updateDetailSignal.emit(self.port_name, 0, "<p>串口已关闭</p>")
            self.finished.emit()  # 发射完成信号

    def execute_report_test(self):
        """执行数据上报测试"""
        try:
            self.updateDetailSignal.emit(self.port_name, 0, "<p>正在执行数据上报测试...</p>")
            
            # 第一步：数据上报
            self.updateStepSignal.emit(self.port_name, 0, "in_progress")
            command = 'AT+CTDIAGNOSE="rda_battery_low_alarm",1,30.8,85\r\n'
            self.updateDetailSignal.emit(self.port_name, 0, f"<p>发送命令: {command.strip()}</p>")
            self.serial.write(command.encode("utf-8"))
            
            report_flag = False
            buffer = ""
            start_time = self.currentTimeMillis()
            timeout = 10000  # 10秒超时
            
            while self.running and (self.currentTimeMillis() - start_time < timeout):
                if report_flag:
                    self.updateDetailSignal.emit(self.port_name, 0, f"<p style='color:green'>数据上报成功</p>")
                    break
                    
                if self.serial.waitForReadyRead(100):
                    response = self.serial.readAll()
                    response_text = response.data().decode("utf-8", errors="replace").strip()
                    buffer += response_text
                    self.updateDetailSignal.emit(self.port_name, 0, f"<p>收到响应: {response_text}</p>")

                    if "OK" in buffer:
                        self.updateDetailSignal.emit(self.port_name, 0, "<p>命令执行成功，正在查询事件上报结果...</p>")
                        report_result = event_report.query_event_report()
                        
                        if report_result["code"] == 0:
                            self.updateDetailSignal.emit(self.port_name, 0, 
                                f"<p style='color:green'>事件上报成功: {report_result.get('message', '')}</p>")
                            self.updateStepSignal.emit(self.port_name, 0, "finished")
                            
                            # 准备开始第二步
                            self.updateDetailSignal.emit(self.port_name, 1, "<p>准备开始指令下发测试...</p>")
                            self.updateStepSignal.emit(self.port_name, 1, "in_progress")
                            report_flag = True
                            return True  # 返回成功标志
                        else:
                            error_msg = report_result.get('message', '未知错误')
                            self.updateDetailSignal.emit(self.port_name, 0, 
                                f"<p style='color:red'>事件上报失败: {error_msg}</p>")
                            self.updateStepSignal.emit(self.port_name, 0, "failed")
                            report_flag = True
                            return False  # 返回失败标志
                else:
                    # 不要打印太多等待信息，避免日志过多
                    pass
                    
            # 检查是否超时
            if not report_flag and self.running:
                self.updateDetailSignal.emit(self.port_name, 0, "<p style='color:red'>数据上报超时</p>")
                self.updateStepSignal.emit(self.port_name, 0, "failed")
                return False  # 返回失败标志
                
        except Exception as e:
            error_msg = str(e)
            self.updateDetailSignal.emit(self.port_name, 0, f"<p style='color:red'>数据上报测试异常: {error_msg}</p>")
            self.updateStepSignal.emit(self.port_name, 0, "failed")
            return False  # 返回失败标志
            
        return False  # 默认返回失败

    def execute_command_test(self):
        """执行指令下发测试"""
        try:
            # 清空缓冲区
            self.serial.clear()
            
            # 记录测试开始
            self.updateDetailSignal.emit(self.port_name, 1, "<p>开始执行指令下发测试...</p>")
            
            # 发送指令下发请求
            self.updateDetailSignal.emit(self.port_name, 1, "<p>正在调用平台API下发指令...</p>")
            issue_result = command_issue.issue_command()
            print("issue_result:", issue_result)
            
            # 检查返回值类型并进行适当处理
            if isinstance(issue_result, bytes):
                # 如果返回的是bytes类型，尝试解码为字符串
                try:
                    issue_result_str = issue_result.decode('utf-8')
                    self.updateDetailSignal.emit(self.port_name, 1, 
                        f"<p style='color:green'>指令下发API调用成功: {issue_result_str}</p>")
                except Exception as decode_error:
                    self.updateDetailSignal.emit(self.port_name, 1, 
                        f"<p style='color:orange'>指令下发API返回二进制数据: {len(issue_result)} 字节</p>")
                
                # 假设API调用成功，继续执行
                command_success = True
            elif isinstance(issue_result, dict):
                # 如果返回的是字典类型，按原逻辑处理
                if issue_result.get("code") != 0:
                    error_msg = issue_result.get("message", "未知错误")
                    self.updateDetailSignal.emit(self.port_name, 1, 
                        f"<p style='color:red'>指令下发API调用失败: {error_msg}</p>")
                    self.updateStepSignal.emit(self.port_name, 1, "failed")
                    return False
                    
                self.updateDetailSignal.emit(self.port_name, 1, 
                    f"<p style='color:green'>指令下发API调用成功: {issue_result.get('message', '')}</p>")
                command_success = True
            else:
                # 其他类型返回值
                self.updateDetailSignal.emit(self.port_name, 1, 
                    f"<p style='color:orange'>指令下发API返回未知类型: {type(issue_result)}</p>")
                if issue_result:
                    command_success = True
                else:
                    self.updateStepSignal.emit(self.port_name, 1, "failed")
                    return False
            
            # 监听设备接收指令
            self.updateDetailSignal.emit(self.port_name, 1, "<p>正在监听设备接收指令...</p>")
            
            # 等待设备接收指令并响应
            buffer = ""
            start_time = self.currentTimeMillis()
            timeout = 30000  # 30秒超时，指令下发可能需要更长时间
            command_received = False
            
            while self.running and (self.currentTimeMillis() - start_time < timeout):
                if self.serial.waitForReadyRead(100):
                    response = self.serial.readAll()
                    response_text = response.data().decode("utf-8", errors="replace").strip()
                    if response_text:
                        buffer += response_text
                        self.updateDetailSignal.emit(self.port_name, 1, f"<p>设备输出: {response_text}</p>")
                        
                        # 检查是否收到指令下发的特征字符串
                        if buffer:
                            self.updateDetailSignal.emit(self.port_name, 1, 
                                "<p style='color:green'>设备成功接收到平台下发的指令</p>")
                            command_received = True
                            break
                else:
                    # 每隔一段时间查询一次指令状态
                    if (self.currentTimeMillis() - start_time) % 5000 < 100:  # 大约每5秒查询一次
                        self.updateDetailSignal.emit(self.port_name, 1, "<p>查询指令执行状态...</p>")
                        try:
                            query_result = command_issue.query_command()
                            # 同样处理可能的bytes返回值
                            if isinstance(query_result, dict) and query_result.get("code") == 0:
                                
                                status = query_result.get("data", {}).get("status")
                                if status == "DELIVERED":
                                    self.updateDetailSignal.emit(self.port_name, 1, 
                                        "<p style='color:green'>平台确认指令已送达设备</p>")
                                elif status == "SUCCESSFUL":
                                    self.updateDetailSignal.emit(self.port_name, 1, 
                                        "<p style='color:green'>平台确认指令已成功执行</p>")
                                    command_received = True
                                    break
                        except Exception as query_error:
                            self.updateDetailSignal.emit(self.port_name, 1, 
                                f"<p style='color:orange'>查询指令状态异常: {str(query_error)}</p>")
            
            # 检查指令是否成功接收
            if not command_received:
                self.updateDetailSignal.emit(self.port_name, 1, "<p style='color:red'>监听设备接收指令超时</p>")
                
                # 最后再查询一次指令状态
                try:
                    query_result = command_issue.query_command()
                    if isinstance(query_result, dict) and query_result.get("code") == 0:
                        status = query_result.get("data", {}).get("status")
                        if status in ["DELIVERED", "SUCCESSFUL"]:
                            self.updateDetailSignal.emit(self.port_name, 1, 
                                f"<p style='color:green'>平台确认指令状态为: {status}</p>")
                            command_received = True
                        else:
                            self.updateDetailSignal.emit(self.port_name, 1, 
                                f"<p style='color:orange'>平台指令状态: {status}</p>")
                except Exception as e:
                    self.updateDetailSignal.emit(self.port_name, 1, 
                        f"<p style='color:orange'>查询指令状态失败: {str(e)}</p>")
                
                if not command_received:
                    self.updateStepSignal.emit(self.port_name, 1, "failed")
                    return False
            
            # 指令下发成功，更新状态
            self.updateStepSignal.emit(self.port_name, 1, "finished")
            
            # 准备开始第三步
            self.updateDetailSignal.emit(self.port_name, 2, "<p>准备开始FOTA升级测试...</p>")
            self.updateStepSignal.emit(self.port_name, 2, "in_progress")
            
            return True
                
        except Exception as e:
            error_msg = str(e)
            self.updateDetailSignal.emit(self.port_name, 1, f"<p style='color:red'>指令下发测试异常: {error_msg}</p>")
            self.updateStepSignal.emit(self.port_name, 1, "failed")
            return False

    def execute_fota_test(self):
        """执行FOTA升级测试"""
        try:
            # 清空缓冲区
            self.serial.clear()
            
            # 记录测试开始
            self.updateDetailSignal.emit(self.port_name, 2, "<p>开始执行FOTA升级测试...</p>")
            
            # 创建FOTA升级器，直接使用QSerialPort对象
            self.updateDetailSignal.emit(self.port_name, 2, "<p>初始化FOTA升级器...</p>")
            fota_upgrader = FOTAUpgrader(
                com_port=self.port_name,
                baud_rate=115200,
                serial_port=self.serial  # 直接使用QSerialPort对象
            )
            
            # 获取当前版本
            self.updateDetailSignal.emit(self.port_name, 2, "<p>获取当前固件版本...</p>")
            current_version = fota_upgrader.get_current_version()
            if not current_version:
                self.updateDetailSignal.emit(self.port_name, 2, "<p style='color:red'>无法获取当前版本</p>")
                self.updateStepSignal.emit(self.port_name, 2, "failed")
                return False
            
            self.updateDetailSignal.emit(self.port_name, 2, f"<p>当前固件版本: {current_version}</p>")
            
            # 设置FTP地址
            ftp_address = "ftp://test:123456@116.247.69.94:13006/CTWing_CTL03_RV_Rev20_V01-V02"
            self.updateDetailSignal.emit(self.port_name, 2, f"<p>使用FTP地址: {ftp_address}</p>")
            
            # 开始升级
            self.updateDetailSignal.emit(self.port_name, 2, "<p>开始FOTA升级...</p>")
            if not fota_upgrader.start_upgrade(ftp_address):
                self.updateDetailSignal.emit(self.port_name, 2, "<p style='color:red'>启动升级失败</p>")
                self.updateStepSignal.emit(self.port_name, 2, "failed")
                return False
            
            # 监控升级进度
            self.updateDetailSignal.emit(self.port_name, 2, "<p>监控升级进度...</p>")
            start_time = self.currentTimeMillis()
            # 增加超时时间到15分钟（900000毫秒），确保有足够时间完成升级
            timeout = 900000  # 15分钟超时
            self.updateDetailSignal.emit(self.port_name, 2, f"<p>设置超时时间: {timeout/60000:.1f}分钟</p>")
            
            # 记录上次进度更新时间和进度值，用于检测进度是否停滞
            last_progress_time = start_time
            last_progress_value = 0
            progress_stall_timeout = 300000  # 5分钟无进度变化则认为停滞
            
            while self.running and (self.currentTimeMillis() - start_time < timeout):
                if fota_upgrader.is_upgrade_complete():
                    self.updateDetailSignal.emit(self.port_name, 2, "<p style='color:green'>FOTA升级成功完成!</p>")
                    self.updateDetailSignal.emit(self.port_name, 2, f"<p>新版本: {fota_upgrader.new_version}</p>")
                    self.updateStepSignal.emit(self.port_name, 2, "finished")
                    
                    # 准备开始第四步
                    self.updateDetailSignal.emit(self.port_name, 3, "<p>准备开始SOTA下载测试...</p>")
                    self.updateStepSignal.emit(self.port_name, 3, "in_progress")
                    
                    return True
                
                if fota_upgrader.is_upgrade_failed():
                    self.updateDetailSignal.emit(self.port_name, 2, "<p style='color:red'>FOTA升级失败!</p>")
                    self.updateStepSignal.emit(self.port_name, 2, "failed")
                    return False
                
                # 获取并显示当前状态和进度
                status = fota_upgrader.get_upgrade_status()
                progress = fota_upgrader.get_upgrade_progress()
                
                # 检查进度是否有更新
                current_time = self.currentTimeMillis()
                if progress != last_progress_value:
                    # 进度有变化，更新最后进度时间和值
                    last_progress_time = current_time
                    last_progress_value = progress
                    self.updateDetailSignal.emit(self.port_name, 2, 
                        f"<p>升级状态: {status}, 进度: {progress}% (已用时间: {(current_time-start_time)/60000:.1f}分钟)</p>")
                elif current_time - last_progress_time > progress_stall_timeout:
                    # 进度长时间未变化，可能卡住了
                    self.updateDetailSignal.emit(self.port_name, 2, 
                        f"<p style='color:orange'>警告: 升级进度已停滞 {progress_stall_timeout/60000:.1f} 分钟，当前进度: {progress}%</p>")
                    
                    # 尝试发送AT命令唤醒设备
                    self.updateDetailSignal.emit(self.port_name, 2, "<p>尝试发送AT命令唤醒设备...</p>")
                    try:
                        fota_upgrader._write(b'AT\r\n')
                        # 重置进度停滞计时器
                        last_progress_time = current_time
                    except Exception as e:
                        self.updateDetailSignal.emit(self.port_name, 2, f"<p style='color:red'>发送AT命令失败: {str(e)}</p>")
                
                # 每30秒显示一次当前状态，避免界面看起来像卡住了
                if (current_time - start_time) % 30000 < 100:
                    elapsed_minutes = (current_time - start_time) / 60000
                    self.updateDetailSignal.emit(self.port_name, 2, 
                        f"<p>升级状态: {status}, 进度: {progress}% (已用时间: {elapsed_minutes:.1f}分钟)</p>")
                
                # 等待一段时间再检查
                time.sleep(2)
            
            # 检查是否超时
            if self.running and (self.currentTimeMillis() - start_time >= timeout):
                elapsed_minutes = timeout / 60000
                self.updateDetailSignal.emit(self.port_name, 2, f"<p style='color:red'>FOTA升级超时，已等待 {elapsed_minutes:.1f} 分钟</p>")
                self.updateStepSignal.emit(self.port_name, 2, "failed")
                return False
            
            # 停止升级监控
            fota_upgrader.stop_upgrade()
            
            return False
                
        except Exception as e:
            error_msg = str(e)
            self.updateDetailSignal.emit(self.port_name, 2, f"<p style='color:red'>FOTA升级测试异常: {error_msg}</p>")
            self.updateStepSignal.emit(self.port_name, 2, "failed")
            return False

    def execute_sota_test(self):
        """执行SOTA下载测试"""
        try:
            # 清空缓冲区
            self.serial.clear()
            
            # 记录测试开始
            self.updateDetailSignal.emit(self.port_name, 3, "<p>开始执行SOTA下载测试...</p>")
            
            # 创建输出文件路径
            file_name = f'sota_download_{self.port_name.replace("/", "_").replace(":", "_")}.bin'
            current_file_path = os.path.dirname(os.path.abspath(__file__))
            output_file = os.path.join(current_file_path, file_name)
            self.updateDetailSignal.emit(self.port_name, 3, f"<p>输出文件: {output_file}</p>")
            
            # 创建SOTA管理器，直接使用QSerialPort对象
            self.updateDetailSignal.emit(self.port_name, 3, "<p>初始化SOTA管理器...</p>")
            sota_manager = SOTAManager(
                com_port=self.port_name,
                baud_rate=115200,
                output_file=output_file,
                ser=self.serial  # 直接使用QSerialPort对象
            )
            
            # 创建读取器
            self.updateDetailSignal.emit(self.port_name, 3, "<p>创建SOTA读取器...</p>")
            reader = SerialReader(
                sota_manager.ser, 
                sota_manager.output_file,
                com_port=sota_manager.com_port,
                baud_rate=sota_manager.baud_rate,
                task_id=181537,  # 任务ID
                device_id=170856841234567,  # 设备ID
                access_token='JnBHGnQsFG',  # 访问令牌
                total_size=202317,  # 数据总大小
                read_len=1024,  # 每次读取的长度
                version='1.0.0'  # 固件版本
            )
            
            # 设置读取器
            sota_manager.reader = reader
            
            # 启动读取器线程
            reader.start()
            self.updateDetailSignal.emit(self.port_name, 3, "<p>SOTA读取器已启动</p>")
            
            # 发送AT指令
            self.updateDetailSignal.emit(self.port_name, 3, "<p>发送AT指令...</p>")
            sota_manager.send_command("ATE0")
            time.sleep(1)
            
            # 发送HTTP URL指令
            self.updateDetailSignal.emit(self.port_name, 3, "<p>发送HTTP URL指令...</p>")
            sota_manager.send_command("AT+QHTTPURL=149,80")
            
            # 等待设备响应
            buffer = ""
            start_time = self.currentTimeMillis()
            timeout = 5000  # 5秒超时
            url_prompt_received = False
            
            while self.running and (self.currentTimeMillis() - start_time < timeout):
                if self.serial.waitForReadyRead(100):
                    response = self.serial.readAll()
                    response_text = response.data().decode("utf-8", errors="replace").strip()
                    buffer += response_text
                    if response_text:
                        self.updateDetailSignal.emit(self.port_name, 3, f"<p>设备响应: {response_text}</p>")
                        if "CONNECT" in response_text:
                            url_prompt_received = True
                            break
            
            if not url_prompt_received:
                self.updateDetailSignal.emit(self.port_name, 3, "<p style='color:red'>未收到URL提示</p>")
                self.updateStepSignal.emit(self.port_name, 3, "failed")
                reader.stop()
                reader.join()
                return False
            
            # 发送URL
            url = "https://iot.ctwing.cn/dmfile/file/mqtt/upgrade?fileId=2fb1f7fc142145cd996e2014313d357e&taskId=181537&deviceId=170856841234567&accessToken=JnBHGnQsFG"
            self.updateDetailSignal.emit(self.port_name, 3, f"<p>发送URL: {url}</p>")
            self.serial.write(url.encode())
            time.sleep(1)
            
            # 发送HTTP GET指令
            self.updateDetailSignal.emit(self.port_name, 3, "<p>发送HTTP GET指令...</p>")
            sota_manager.send_command("AT+QHTTPGETEX")
            
            # 监控下载进度
            self.updateDetailSignal.emit(self.port_name, 3, "<p>监控下载进度...</p>")
            start_time = self.currentTimeMillis()
            timeout = 300000  # 5分钟超时
            
            while self.running and (self.currentTimeMillis() - start_time < timeout):
                if sota_manager.is_download_complete():
                    # 下载完成后获取MD5
                    md5 = sota_manager.get_md5()
                    self.updateDetailSignal.emit(self.port_name, 3, f"<p style='color:green'>下载完成，MD5签名: {md5}</p>")
                    self.updateStepSignal.emit(self.port_name, 3, "finished")
                    
                    # 所有测试完成
                    self.updateDetailSignal.emit(self.port_name, 3, "<p style='color:green'>所有测试步骤已完成!</p>")
                    
                    return True
                
                # 获取并显示当前进度
                progress = sota_manager.get_progress()
                self.updateDetailSignal.emit(self.port_name, 3, f"<p>下载进度: {progress}%</p>")
                
                # 等待一段时间再检查
                time.sleep(2)
            
            # 检查是否超时
            if self.running and (self.currentTimeMillis() - start_time >= timeout):
                self.updateDetailSignal.emit(self.port_name, 3, "<p style='color:red'>SOTA下载超时</p>")
                self.updateStepSignal.emit(self.port_name, 3, "failed")
                reader.stop()
                reader.join()
                return False
            
            # 停止读取器
            reader.stop()
            reader.join()
            
            return False
                
        except Exception as e:
            error_msg = str(e)
            self.updateDetailSignal.emit(self.port_name, 3, f"<p style='color:red'>SOTA下载测试异常: {error_msg}</p>")
            self.updateStepSignal.emit(self.port_name, 3, "failed")
            return False
    
    def currentTimeMillis(self):
        """获取当前时间的毫秒值"""
        import time
        return int(round(time.time() * 1000))